//
//  RWTBaseEffect.m
//  HelloOpenGL
//
//  Created by Ray Wenderlich on 9/3/13.
//  Copyright (c) 2013 Ray Wenderlich. All rights reserved.
//

#import "RWTBaseEffect.h"
#import "RWTVertex.h"
#import <OpenGLES/ES2/glext.h>

@implementation RWTBaseEffect {
    GLuint _programHandle;
    GLuint _modelViewMatrixUniform;//Uniform projectionMatrix
    GLuint _projectionMatrixUniform;//Uniform
    GLuint _textureUniform;//Texture Uniform
    GLuint _lightColorUniform;//lightColor Uniform
    GLuint _lightAmbientIntensityUniform;//lightAmbientIntensity Uniform
    GLuint _lightDiffuseIntensityUniform;//lightDiffuseIntensity Uniform
    GLuint _lightDirectionUniform;//lightDirection Uniform
    GLuint _matSpecularIntensityUniform;//SpecularIntensity Uniform
    GLuint _shininessUniform;//shininess Uniform
    
}

- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
  NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:nil];
  NSError* error;
  NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
  if (!shaderString) {
    NSLog(@"Error loading shader: %@", error.localizedDescription);
    exit(1);
  }
  
  GLuint shaderHandle = glCreateShader(shaderType);
  
  const char * shaderStringUTF8 = [shaderString UTF8String];
  int shaderStringLength = [shaderString length];
  glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
  
  glCompileShader(shaderHandle);
  
  GLint compileSuccess;
  glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
  if (compileSuccess == GL_FALSE) {
    GLchar messages[256];
    glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
    NSString *messageString = [NSString stringWithUTF8String:messages];
    NSLog(@"%@", messageString);
    exit(1);
  }
  
  return shaderHandle;
}

- (void)compileVertexShader:(NSString *)vertexShader
             fragmentShader:(NSString *)fragmentShader {
  GLuint vertexShaderName = [self compileShader:vertexShader
                                       withType:GL_VERTEX_SHADER];
  GLuint fragmentShaderName = [self compileShader:fragmentShader
                                         withType:GL_FRAGMENT_SHADER];
  
  _programHandle = glCreateProgram();
  glAttachShader(_programHandle, vertexShaderName);
  glAttachShader(_programHandle, fragmentShaderName);
  
  glBindAttribLocation(_programHandle, RWTVertexAttribPosition, "a_Position");
  glBindAttribLocation(_programHandle, RWTVertexAttribColor, "a_Color");
//    //绑定纹理坐标
    glBindAttribLocation(_programHandle, RWTVertexAttribTextCoord, "a_TexCoord");
    //绑定法线
    glBindAttribLocation(_programHandle, RWTVertexAttribNormal, "a_Normal");
  glLinkProgram(_programHandle);
  
    //初始化模型矩阵
    self.modelViewMatrix = GLKMatrix4Identity;
    _modelViewMatrixUniform = glGetUniformLocation(_programHandle, "u_ModelViewMatrix");
    _projectionMatrixUniform = glGetUniformLocation(_programHandle, "u_ProjectionMatrix");
    _textureUniform = glGetUniformLocation(_programHandle, "u_Texture");
    //环境光
    _lightColorUniform = glGetUniformLocation(_programHandle, "u_Light.Color");
    _lightAmbientIntensityUniform = glGetUniformLocation(_programHandle, "u_Light.AmbientIntensity");
    //漫反射
    _lightDiffuseIntensityUniform = glGetUniformLocation(_programHandle, "u_Light.DiffuseIntensity");
    _lightDirectionUniform = glGetUniformLocation(_programHandle, "u_Light.Direction");
    //镜面反射
    _matSpecularIntensityUniform = glGetUniformLocation(_programHandle, "u_MatSpecularIntensity");
    _shininessUniform = glGetUniformLocation(_programHandle, "u_Shininess");
  GLint linkSuccess;
  glGetProgramiv(_programHandle, GL_LINK_STATUS, &linkSuccess);
  if (linkSuccess == GL_FALSE) {
    GLchar messages[256];
    glGetProgramInfoLog(_programHandle, sizeof(messages), 0, &messages[0]);
    NSString *messageString = [NSString stringWithUTF8String:messages];
    NSLog(@"%@", messageString);
    exit(1);
  }
}

- (void)prepareToDraw {
  glUseProgram(_programHandle);
    //为 modelViewMatix赋值
    glUniformMatrix4fv(_modelViewMatrixUniform, 1, 0, self.modelViewMatrix.m);
    //为 projectionMatrix赋值
    glUniformMatrix4fv(_projectionMatrixUniform, 1, 0, self.projectionMatrix.m);

    //纹理相关
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, self.texture);
    glUniform1i(_textureUniform, 1);
    
    //光照相关
    //环境光颜色
    glUniform3f(_lightColorUniform, 1, 1, 1);
    //环境光强度
    glUniform1f(_lightAmbientIntensityUniform, 0.1);
    //环境光方向
    GLKVector3 lightDirection = GLKVector3Normalize(GLKVector3Make(0, 1, -1));
    glUniform3f(_lightDirectionUniform, lightDirection.x, lightDirection.y, lightDirection.z);
    //环境光漫反射强度
    glUniform1f(_lightDiffuseIntensityUniform, 0.7);
    
    //镜面反射
    //镜面反射光强度
    glUniform1f(_matSpecularIntensityUniform, 2.0);
    //镜面反射光亮度
    glUniform1f(_shininessUniform, 8.0);
    
}

- (instancetype)initWithVertexShader:(NSString *)vertexShader fragmentShader:
(NSString *)fragmentShader {
  if ((self = [super init])) {
    [self compileVertexShader:vertexShader fragmentShader:fragmentShader];
  }
  return self;
}

@end
